package com.byron.media.server.handlers;

import com.byron.media.server.enums.MediaType;
import com.byron.media.server.enums.ProxyType;
import com.byron.media.server.model.DataFactory;
import com.byron.media.server.model.MediaData;
import com.byron.media.server.model.ProxyMediaData;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.nio.charset.StandardCharsets;
import java.util.List;

//@ChannelHandler.Sharable
public class MediaDecoder extends ByteToMessageDecoder {

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        int remain = in.readableBytes();
        if(remain < 15){
            return;
        }

        int originIndex = in.readerIndex();
        in.markReaderIndex(); // 标记读取的位置,方便后面reset

        byte firstByte = in.readByte();

        // RTP 数据
        if(firstByte == '$'){
            int readable = in.readableBytes();

            // RTSP 协议数据
            decodeRtp(originIndex, ctx, in, out);
        } else{

            in.resetReaderIndex();
            decodeString(originIndex, ctx, in, out);
        }
    }


    private boolean decodeRtp(int originIndex, ChannelHandlerContext ctx, ByteBuf in, List<Object> out){
        byte channel = in.readByte();
        byte type = in.readByte();
//        long ID = in.readLong();
        int id = in.readInt();
//        byte serverIdSeq = in.readByte();
        byte seq = in.readByte();
        byte serverId = in.readByte();
//        byte serverId = (byte) (serverIdSeq & 0xFF);
//        byte seq = (byte)((serverIdSeq >> 4) & 0xFF);
//        byte noUseByte = in.readByte();
        short noUseShort = in.readShort();

        int length = in.readInt();
        int readable = in.readableBytes();

        if(length > readable){
            in.resetReaderIndex();
            return false;
        }

        if(length < 0){
            in.resetReaderIndex();
            return false;
        }

        if(MediaType.isProxy(type)){
//            ProxyMediaData proxyData = new ProxyMediaData();

            byte proxyType = in.readByte();
            long sessionName = in.readLong();
            if(proxyType == ProxyType.MEDIA_DATA){

                short groupNameLength = in.readShort();
                byte[] groupNameBytes = new byte[groupNameLength];
                in.readBytes(groupNameBytes);
                String groupName = new String(groupNameBytes, StandardCharsets.UTF_8);

                byte mediaType = in.readByte();
                int mediaLength = in.readInt();
                MediaData media = DataFactory.getInstance().createData(mediaLength);

                in.readBytes(media.getData(), 0, mediaLength);
                media.setChannel(channel);
                media.setType(mediaType);
                media.setLength(mediaLength);
                media.setID(id);
                media.setSeq(seq);
                media.setServerId(serverId);

                out.add(new ProxyMediaData(sessionName, groupName, media));
            } else if(proxyType == ProxyType.JSON){
                byte[] buffer = new byte[length - 9];
                in.readBytes(buffer);
                out.add(new ProxyMediaData(sessionName, seq, serverId, new String(buffer, StandardCharsets.UTF_8)));
            }

        } else {
            MediaData media = DataFactory.getInstance().createData(length);
            in.readBytes(media.getData(), 0, length);
            media.setChannel(channel);
            media.setType(type);
//            media.setFromWireless(MediaType.isFromWireless(type));
            media.setLength(length);
            media.setID(id);
            media.setSeq(seq);
            media.setServerId(serverId);

            out.add(media);
        }
        return true;
    }

    private boolean decodeString(int originIndex, ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
        in.markReaderIndex();

        int read = 0;
        while (in.readableBytes() > 0) {
            byte b = in.readByte();
            read ++;

            if(b == (byte)'\n' || b == (byte)'\r'){

//                int length = in.readerIndex();
                in.resetReaderIndex();
                byte[] data = new byte[read];
                in.readBytes(data);
                String str = new String(data);
                out.add(str);
                return true;
            }
        }

        in.resetReaderIndex();
        return false;
    }
}
